package es.index.logs.parse;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import es.index.util.EncodingDetect;
import es.index.util.ProduceIndexID;

public abstract class LogsBaseParse extends LogsParse {

	protected FileInputStream _fis = null;

	protected InputStreamReader _isr = null;

	/**
	 * 用于包装InputStreamReader,提高处理性能。因为BufferedReader有缓冲的，而InputStreamReader没有。
	 */
	protected BufferedReader _br = null;

	/**
	 * 当前读取的行，以及解析之后的剩余信息
	 */
	protected String _line = "";

	/**
	 * 当前从_line解析出来的信息
	 */
	protected String _item = "";

	/**
	 * 当前解析index值
	 */
	protected int _index = 0;

	protected int M = 0;// 月
	protected int y = 0;// 年
	protected int d = 0;// 日
	protected int h = 0;// 时
	protected int m = 0;// 分
	protected int s = 0;// 秒

	/**
	 * 文件名称
	 */
	protected String _fileName = "";

	/**
	 * 存储属性对应set方法
	 */
	protected Map<String, String> _map = null;

	/**
	 * 解析类属性，用于动态设置 类属性值
	 * 
	 * @param aClazz
	 *            需要解析的类类型
	 * @param aFieldName
	 *            解析的属性字符串表示形式
	 * @return Field
	 */
	public static Field getClassField(Class<?> clazz, String aFieldName) {
		Field[] declaredFields = clazz.getDeclaredFields();
		for (Field field : declaredFields) {
			// 注意：这里判断的方式，是用字符串的比较。很傻瓜，但能跑。要直接返回Field。我试验中，尝试返回Class，然后用getDeclaredField(String
			// fieldName)，但是，失败了
			if (field.getName().equals(aFieldName)) {
				return field;// define in this class
			}
		}

		Class<?> superclass = clazz.getSuperclass();
		if (superclass != null) {// 简单的递归一下
			return getClassField(superclass, aFieldName);
		}
		return null;
	}

	@Override
	public List<?> inputLogs(File file) throws Exception {
		if (!file.exists())
			throw new Exception("无效的文件地址" + file.getAbsolutePath());
		List<Object> list = new ArrayList<Object>();

		try {
			_fis = new FileInputStream(file);// FileInputStream
			// 从文件系统中的某个文件中获取字节
			// InputStreamReader 是字节流通向字符流的桥梁,
			_isr = new InputStreamReader(_fis,
					EncodingDetect.getJavaEncode(file.getAbsolutePath()));
			// 从字符输入流中读取文件中的内容,封装了一个 new InputStreamReader的对象
			_br = new BufferedReader(_isr);

			_fileName = file.getName();

			initParseParamete();

			parse(file, list);
		} catch (Exception e) {
			throw new Exception("文件解析失败,错误信息:" + e.getMessage());
			// logger.info("IOException error!，失败信息:" + e.getMessage());
		} finally {
			close();
		}

		return list;
	}

	@Override
	public List<?> inputLogs(String name, StringBuffer buffer) throws Exception {
		return null;
	}

	@Override
	public List<?> inputLogs(String path) throws Exception {
		File file = new File(path);
		return inputLogs(file);
	}

	@Override
	public List<?> inputLogs(String[] paths) throws Exception {
		List<Object> list = new ArrayList<Object>();
		for (int i = 0; i < paths.length; i++) {
			File file = new File(paths[i]);
			@SuppressWarnings("unchecked")
			List<Object> list1 = (List<Object>) inputLogs(file);
			list.addAll(list1);
		}
		return list;
	}

	public void parse(File file, List<Object> list) throws IOException {
		while ((_line = _br.readLine()) != null) {
			list.add(getLogs());
		}
	}

	/**
	 * 生产唯一ID
	 * 
	 * @return
	 */
	protected String ID() {
		try {
			return ProduceIndexID.getFiledID();
		} catch (Exception e) {
		}
		return "";
		// if (_idObject != null) {
		// try {
		// Method getID = _idObject.getClass().getDeclaredMethod("getFiledID");
		// getID.setAccessible(true);
		// if (getID != null) {
		// return getID.invoke(_idObject).toString();
		// }
		// } catch (NoSuchMethodException e) {
		// logger.info("ID获取失败，失败信息:" + e.getMessage());
		// } catch (SecurityException e) {
		// logger.info("ID获取失败，失败信息:" + e.getMessage());
		// } catch (IllegalAccessException e) {
		// logger.info("ID获取失败，失败信息:" + e.getMessage());
		// } catch (IllegalArgumentException e) {
		// logger.info("ID获取失败，失败信息:" + e.getMessage());
		// } catch (InvocationTargetException e) {
		// logger.info("ID获取失败，失败信息:" + e.getMessage());
		// }
		// }
		// return "";
	}

	/**
	 * 初始化解析参数，即初始化 _map = null 和 _keys = null;
	 */
	protected void initParseParamete() {
	}

	protected void initParseParamete(Class<?> t) {
		Method[] methods = t.getDeclaredMethods();
		_map = new HashMap<String, String>();

		String mName = "";
		for (Method method : methods) {
			mName = method.getName();
			if (mName.startsWith("set"))
				_map.put(mName, mName);
		}
	}

	/**
	 * 生产一个对象
	 * 
	 * @return
	 */
	protected Object getLogs() {
		return null;
	}

	/**
	 * 获取类的set方法
	 * 
	 * @param t
	 *            Class
	 * @return Map<String, Method>
	 */
	protected Map<String, Method> getClassSetMethod(Class<?> t) {
		Method[] methods = t.getMethods();
		Map<String, Method> methodMap = new HashMap<String, Method>();
		for (Method method : methods) {
			if (method.getName().startsWith("set")) {
				for (String key : _keys) {
					if (_map.containsKey(key)) {
						if (_map.get(key).equals(method.getName())) {
							methodMap.put(_map.get(key), method);
							break;
						}
					}
				}
			}
		}
		return methodMap;
	}

	/**
	 * 反射并设置相关属性
	 * 
	 * @param object
	 * @param methodMap
	 * @param map
	 * @param keys
	 * @param startIndex
	 * @param regex
	 * @param replacement
	 */
	protected void setClassValue(Object object, int startIndex, String regex,
			String replacement) {

		Map<String, Method> methodMap = getClassSetMethod(object.getClass());

		int index = startIndex;

		while (!_line.equals("")) {
			getNextValue(regex, replacement, _map.get(_keys[index]), index);

			Method method = methodMap.get(_map.get(_keys[index++]));

			try {
				Class<?>[] _parameterTypes = method.getParameterTypes();
				if (_parameterTypes[0].equals(Integer.TYPE)) {
					// method.invoke(object, Integer.parseInt(_item));
					setObjectIntValue(method, object, _item);
				} else if (_parameterTypes[0].equals(String.class)) {
					// method.invoke(object, _item);
					setObjectStringValue(method, object, _item);
				} else if (_parameterTypes[0].equals(Date.class)) {
					setObjectDateValue(method, object);
				} else if (_parameterTypes[0].equals(Long.TYPE)) {
					setObjectLongValue(method, object, _item);
				}
			} catch (Exception e) {
				// logger.info("设置失败!，失败信息:" + e.getStackTrace());
			}
		}
	}

	/**
	 * 解析下一个项目的值
	 * 
	 * @param regex
	 *            替换解析完成之后的文本内容
	 * @param replacement
	 *            需要把regex的内容替换为该replacement
	 * 
	 * @param methodName
	 *            当前解析的字段 set方法字符串名称
	 * 
	 * @param currentIndex
	 *            表示该值在_keys中的坐标
	 */
	protected void getNextValue(String regex, String replacement,
			String methodName, int currentIndex) {
		getNextIndex(methodName, currentIndex);

		if (_index == -1)
			_index = _line.length();
		_item = new String(_line.substring(0, _index));
		_line = new String(_line.substring(_index).trim());

		if (regex != null && replacement != null)
			_item = _item.replaceAll("[\\[|\\]|\"]", "");// 去除字符串中包含的如下特殊符号[,],"
	}

	/**
	 * 解析下一个项目的index值
	 * 
	 * @param methodName
	 *            当前解析的字段 set方法字符串名称
	 * @param currentIndex
	 *            表示该值在_keys中的坐标
	 */
	protected void getNextIndex(String methodName, int currentIndex) {
		if (currentIndex == _keys.length - 1) {
			_index = _line.length();
		} else {
			_index = _line.indexOf(' ');
		}
	}

	/**
	 * 设置 Object 的 long 属性
	 * 
	 * @param method
	 *            反射的方法
	 * @param object
	 *            反射对象
	 * @param value
	 *            操作值
	 * @throws NumberFormatException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
	protected void setObjectLongValue(Method method, Object object, String value)
			throws NumberFormatException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException {
		method.invoke(object, Long.parseLong(value, 16));
	}

	/**
	 * 设置 Object 的 Int 属性
	 * 
	 * @param method
	 *            反射的方法
	 * @param object
	 *            反射对象
	 * @param value
	 *            操作值
	 * @throws NumberFormatException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
	protected void setObjectIntValue(Method method, Object object, String value)
			throws NumberFormatException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException {
		method.invoke(object, Integer.parseInt(value));
	}

	/**
	 * 设置 Object 的 String 属性
	 * 
	 * @param method
	 *            反射的方法
	 * @param object
	 *            反射对象
	 * @param value
	 *            操作值
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
	protected void setObjectStringValue(Method method, Object object,
			String value) throws IllegalAccessException,
			IllegalArgumentException, InvocationTargetException {
		method.invoke(object, value);
	}

	/**
	 * 设置 Object 的 Date 属性
	 * 
	 * @param method
	 *            反射的方法
	 * @param object
	 *            反射对象
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
	protected void setObjectDateValue(Method method, Object object)
			throws IllegalAccessException, IllegalArgumentException,
			InvocationTargetException {
		method.invoke(object, getDate());
	}

	/**
	 * 计算时间
	 * 
	 * @return
	 */
	protected Date getDate() {
		return null;
	}

	protected Date getDefaultDate() {
		String[] dateArray = _item.split("[/|:]");

		getDateField(dateArray, new String[] { "d", "M", "y", "h", "m", "s" },
				true);

		return getDates(M - 1, y, d, h, m, s);
	}

	/**
	 * 计算例如"1067299212.411"类似的时间
	 * 
	 * @return
	 */
	protected Date getNumDate() {
		_index = _item.indexOf('.');
		String millis = "";
		String millisecond = "";
		if (_index == -1) {
			millisecond = _item;
		} else {
			millis = new String(_item.substring(0, _index));
			millisecond = new String(_item.substring(_index + 1));
		}

		@SuppressWarnings("unused")
		char ch = '\0';
		while ((ch = millisecond.charAt(0)) == '0') {
			millisecond = new String(millisecond.substring(1));
		}

		Calendar calendar = Calendar.getInstance();
		try {
			calendar.setTimeInMillis(Long.parseLong(millis));
			calendar.set(Calendar.MILLISECOND, Integer.parseInt(millisecond));
		} catch (NumberFormatException e) {
		}
		return calendar.getTime();
	}

	/**
	 * 根据 dates 计算 parse 顺序的时间值
	 * 
	 * @param dates
	 *            存储 ymd hms 值
	 * @param parse
	 *            控制 ymd hms 顺序
	 * @param isGetMonthB
	 *            控制月份的获取方式，是直接转换还是通过 GetMonthByString.month方法获取
	 * @return
	 */
	protected boolean getDateField(String[] dates, String[] parse,
			boolean isGetMonthB) {
		for (int i = 0; i < parse.length; i++) {
			Field field = getClassField(getClass(), parse[i]);
			if (field != null) {
				try {
					if (isGetMonthB && parse[i].equals("M")) {
						field.set(this, GetMonthByString.month(dates[i].trim()));
					} else if (parse[i].equals("h")) {
						int h = Integer.parseInt(dates[i].trim());
						if (isGetMonthB && dates.length == 6) {
							field.set(this, h + getPMNumber(dates[5].trim()));
						} else {
							field.set(this, h);
						}
					} else {
						field.set(this, Integer.parseInt(dates[i].trim()));
					}
				} catch (Exception e) {
					// logger.info("设置失败!，失败信息:" + e.getStackTrace());
					// System.out.println("数据转换失败！当前进行转换的数据" + dates[i].trim());
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * 根据已知的年月日时分秒生产一个 Date对象
	 * 
	 * @param month
	 * @param year
	 * @param dar
	 * @param h
	 * @param m
	 * @param s
	 * @return
	 */
	protected Date getDates(int month, int year, int dar, int h, int m, int s) {
		Calendar c = Calendar.getInstance();
		c.set(year, month, dar, h, m, s);
		return c.getTime();
	}

	/**
	 * 如果pm表示是下午，则返回12，用于计算24小时日期格式
	 * 
	 * @param pm
	 * @return
	 */
	protected int getPMNumber(String pm) {
		pm = pm.toLowerCase();
		if (pm.equals("下午") || pm.equals("pm") || pm.equals("p.m."))
			return 12;
		return 0;
	}

	/**
	 * 关闭与文件操作相关的对象
	 */
	protected void close() {
		try {
			if (_fis != null)
				_fis.close();
		} catch (IOException e) {
			// e.printStackTrace();
			// logger.info("关闭失败!，失败信息:" + e.getStackTrace());
		}
		_fis = null;
		try {
			if (_isr != null)
				_isr.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		_isr = null;
		try {
			if (_br != null)
				_br.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		_br = null;
	}
}
